package com.mmd.tencent.service.impl;

import com.mmd.base.utils.DateUtils;
import com.mmd.tencent.config.WechatConfig;
import com.mmd.tencent.config.WechatUrlConfig;
import com.mmd.tencent.entity.AccessTokenEntity;
import com.mmd.tencent.entity.GenerateEntity;
import com.mmd.tencent.entity.OpenLinkEntity;
import com.mmd.tencent.service.WechatService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@ConditionalOnProperty(name = "appid",prefix = "wechat.public")
public class WechatServiceImpl implements WechatService {
    @Autowired
    private WechatConfig wechatConfig;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private RedissonClient redissonClient;

    private String accessTokenKey = "accessToken";

    /**
     * 获取小程序accessToken
     */
    public String getAccessToken()
    {
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
        String accessTokenStr = valueOperations.get(accessTokenKey);
        if(!StringUtils.isEmpty(accessTokenStr)) return accessTokenStr;
        RLock accessToken = redissonClient.getLock(accessTokenKey);
        try {
            // 获取锁
            if(!accessToken.tryLock(10L, 5L, TimeUnit.SECONDS)){
                log.error("获取AccessToken等待10秒结束后未获取到锁,重新调用方法");
                // 等待结束后未获取到锁重新调用
                return getAccessToken();
            }
            log.info("获取AccessToken锁成功");
            String url = WechatUrlConfig.accessTokenUrlMini
                    .replace("{appid}", wechatConfig.getAppid())
                    .replace("{appsecret}", wechatConfig.getAppSecret());
            ResponseEntity<AccessTokenEntity> forEntity = restTemplate.getForEntity(url, AccessTokenEntity.class);
            AccessTokenEntity accessTokenEntity = forEntity.getBody();
            log.info("获取AccessToken成功=>"+accessTokenEntity);
            if(accessTokenEntity == null) return "";
            valueOperations.set(accessTokenKey,accessTokenEntity.getAccess_token(),accessTokenEntity.getExpires_in() - 200L, TimeUnit.SECONDS);
            return valueOperations.get(accessTokenKey);
        } catch (InterruptedException e) {
            // 报错重新调用
            log.error("获取AccessToken报错然后重新调用,报错信息"+e.getMessage());
            return getAccessToken();
        }finally {
            log.info("获取AccessToken成功解除锁");
            accessToken.unlock();
        }
    }

    /**
     * 获取h5跳转小程序路径
     * @param query 如需json对 穿 key=value
     */
    public OpenLinkEntity generate(String query)
    {
        String accessToken = getAccessToken();
        String url = WechatUrlConfig.generateUrl.replace("{accesstoken}", accessToken);
        GenerateEntity.JumpWxa jumpWxa = new GenerateEntity.JumpWxa();
        jumpWxa.setPath("/pages/index/index");
        jumpWxa.setQuery(query);
        jumpWxa.setEnv_version("trial");
        Map<String, Object> map = new HashMap<>();
        map.put("jump_wxa",jumpWxa);
        map.put("is_expire",true);
        map.put("expire_type",0);
        // 失效时间 增加180天
        Date date = DateUtils.assignDateAddTime(new Date(), 180, Calendar.DATE);
        map.put("expire_time",date.getTime()/1000);
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        /*HashMap是以请求体传递，MultiValueMap是表单传递！*/
        HttpEntity<Map<String, Object>> httpEntity = new HttpEntity<>(map, httpHeaders);
        ResponseEntity<OpenLinkEntity> openLinkEntityResponseEntity = restTemplate.postForEntity(url, httpEntity, OpenLinkEntity.class);
        return openLinkEntityResponseEntity.getBody();
    }
}
